#include "include/FFmpegPlay.h"
#include "include/Constant.h"

FFmpegPlay::FFmpegPlay(JniCallJava *jniCallJava, const char *mediaUrl) {
    this->pJniCallJava = jniCallJava;
    // 重新复制一份 mediaUrl (防止外部调用者调用该方法后销毁了 mediaUrl)
    this->mediaUrl = static_cast<char *>(malloc(strlen(mediaUrl) + 1));
    memcpy(this->mediaUrl, mediaUrl, strlen(mediaUrl) + 1);
}

FFmpegPlay::~FFmpegPlay() {
    release();
}

void FFmpegPlay::play() {
    if (pAudioPlay != nullptr) {
        pAudioPlay->play();
    }
}

void FFmpegPlay::prepare() {
    prepare(THREAD_MAIN);
}

void *preparePlay(void *context) {
    FFmpegPlay *fFmpegPlay = (FFmpegPlay *) context;
    fFmpegPlay->prepare(THREAD_CHILD);
    return nullptr;
}

void FFmpegPlay::prepareAsync() {
    pthread_t prepareThread;
    pthread_create(&prepareThread, NULL, preparePlay, this);
    pthread_detach(prepareThread);
}

void FFmpegPlay::prepare(ThreadMode threadMode) {
    avformat_network_init();
    int av_fmt_open_input_res = 0;
    int av_fmt_find_stream_info_res = 0;
    int av_audio_stream_index = 0;


    // 封装格式上下文，统领全局的结构体，保存了视频文件封装格式的相关信息
    pAvFormatContext = avformat_alloc_context();

    av_fmt_open_input_res = avformat_open_input(&pAvFormatContext, mediaUrl, nullptr, nullptr);
    if (av_fmt_open_input_res) {
        LOGE("av format open input error: %s", av_err2str(av_fmt_open_input_res));
        callOnError(threadMode, av_fmt_open_input_res, av_err2str(av_fmt_open_input_res));
        return;
    }

    av_fmt_find_stream_info_res = avformat_find_stream_info(pAvFormatContext, nullptr);
    if (av_fmt_find_stream_info_res < 0) {
        LOGE("av format find stream info error: %s", av_err2str(av_fmt_find_stream_info_res));
        callOnError(threadMode, av_fmt_find_stream_info_res,
                    av_err2str(av_fmt_find_stream_info_res));
        return;
    }

    // 查找音频流的 index
    av_audio_stream_index = av_find_best_stream(pAvFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1,
                                                nullptr,
                                                0);
    if (av_audio_stream_index < 0) {
        LOGE("av format find best stream error.");
        callOnError(threadMode, AV_FORMAT_FIND_BEST_STREAM_ERROR_CODE,
                    const_cast<char *>("av format find best stream error"));
        return;
    }

    pAudioPlay = new AudioPlay(pAvFormatContext, pJniCallJava, av_audio_stream_index);
    pAudioPlay->analyzeStream(threadMode);

    // =========== 重采样 end ===========

    pJniCallJava->callOnPrepared(threadMode);

}

void FFmpegPlay::callOnError(ThreadMode threadMode, int errorCode, char *errorMsg) {
    release();
    if (pJniCallJava != nullptr) {
        pJniCallJava->callOnError(threadMode, errorCode, errorMsg);
    }
}

void FFmpegPlay::release() {
    if (pAvFormatContext != nullptr) {
        avformat_close_input(&pAvFormatContext);
        avformat_free_context(pAvFormatContext);
        pAvFormatContext = nullptr;
    }

    avformat_network_deinit();

    if (mediaUrl != nullptr) {
        free(mediaUrl);
        mediaUrl = nullptr;
    }
}